package upm.pb4agent.team2;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import upm.pb4agent.ontology.PB4AgentOntology;
import upm.pb4agent.team2.internalOntology.Team2InternalOntology;
import jade.content.lang.Codec;
import jade.content.lang.Codec.CodecException;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.content.onto.OntologyException;
import jade.content.onto.basic.Action;
import jade.core.AID;
import jade.core.Agent;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.util.leap.Properties;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;
import jade.wrapper.ControllerException;

/**
 * Agent subclass to serve as superclass to Team2's agents
 * 
 * @author Alejandro Bustamante
 * @version 1.0
 */

public class Team2BaseAgent extends Agent 
{
	private static final long serialVersionUID = 1886047915421694672L;


	protected Codec codec = new SLCodec();
	protected Ontology ontology = PB4AgentOntology.getInstance();
	protected Ontology internalOntology = Team2InternalOntology.getInstance();
	private static final Properties properties = new Properties();
	
	protected void setup() 
	{
		printEntered();
		
		getContentManager().registerLanguage(codec);
		getContentManager().registerOntology(ontology);
		getContentManager().registerOntology(internalOntology);
	}
	
	protected void sendInternalMessage(AID receiverAID, int performative, Action ontologyAction, String protocol)
	{
		ACLMessage aclMessage = createInternalACLMessage(performative);
		aclMessage.addReceiver(receiverAID);
		aclMessage.addReplyTo(this.getAID());
		aclMessage.setProtocol(protocol);

		try 
		{
			if (ontologyAction != null)
			{
				getContentManager().fillContent(aclMessage, ontologyAction);
			}
			send(aclMessage);
		} 
		catch (CodecException ce) 
		{
			ce.printStackTrace();
		} 
		catch (OntologyException oe) 
		{
			oe.printStackTrace();
		}
	}
	
	protected void sendMessage(AID receiverAID, int performative, Action ontologyAction, String protocol)
	{
		ACLMessage aclMessage = createACLMessage(performative);
		aclMessage.addReceiver(receiverAID);
		aclMessage.addReplyTo(this.getAID());
		aclMessage.setProtocol(protocol);

		try 
		{
			if (ontologyAction != null)
			{
				getContentManager().fillContent(aclMessage, ontologyAction);
			}
			send(aclMessage);
		} 
		catch (CodecException ce) 
		{
			ce.printStackTrace();
		} 
		catch (OntologyException oe) 
		{
			oe.printStackTrace();
		}
	}
	

	protected void sendStringMessage(AID receiverAID, int performative, String stringMessage)
	{
		ACLMessage aclMessage = createACLMessage(performative);
		aclMessage.addReceiver(receiverAID);
		aclMessage.addReplyTo(this.getAID());
		aclMessage.setContent(stringMessage);
		aclMessage.setProtocol(stringMessage);
		send(aclMessage);
	}
	
	public String getPropertyFromConfigFile(String key) throws FileNotFoundException, IOException 
	{
		String value = null;
		
		properties.load(new FileInputStream(Constants.CONFIG_FILENAME));
		value = properties.getProperty(key);
		
		return value;
	}
	
	protected boolean registerOnDF(String serviceType)
	{
		Boolean result = false;
		try 
		{
			// Create own service description
			ServiceDescription sd = new ServiceDescription();
			sd.setName(this.getName());
			sd.setType(serviceType);
			
			// Create own agent description
			DFAgentDescription dfd = new DFAgentDescription();
			// Add service description to agent description
			dfd.addServices(sd);
			
			// Register on DFService
			DFService.register(this, dfd);
			
			// destroy references
			dfd = null;
			sd = null;
			
			printOut("-> registered in the DF -");
		} 
		catch (FIPAException e) 
		{
			result = false;
			
			e.printStackTrace();
		}
		
		return result;
	}
	
	protected AID findAgentOnDF(Agent agent, String serviceType)
	//protected AID findAgentOnDF(String serviceType)
	{
		AID aid = null;
		
		DFAgentDescription dfAgentDescription = new DFAgentDescription();
		ServiceDescription serviceDescription = new ServiceDescription();
		serviceDescription.setType(serviceType);
		dfAgentDescription.addServices(serviceDescription);

		DFAgentDescription[] result;
		
		try 
		{
			result = null;
			
			//fix for intermittent crash on Team1's AgPlatform - forcing agents to be found
			while(result == null)
			{
				result = DFService.search(agent, dfAgentDescription);
			}
			
			if (result.length == 1) 
			{
				aid = (AID) result[0].getName();
			}
			else
			{
				printOut(" *** findAgentOnDF() CALL FAILED !! *** - search result produced " + result.length + " AIDs for serviceType: "+serviceType);
			}
			
		}
		catch (FIPAException e) 
		{
			printOut(" exception at Team2BaseAgent.findAgentOnDF()");
		}
		
		return aid;
	}
	
	protected ACLMessage createInternalACLMessage(int performative)
	{
		ACLMessage aclMessage = new ACLMessage(performative);
		aclMessage.setLanguage(codec.getName());
		aclMessage.setOntology(internalOntology.getName());
		
		return aclMessage;
	}
	
	protected ACLMessage createACLMessage(int performative)
	{
		ACLMessage aclMessage = new ACLMessage(performative);
		aclMessage.setLanguage(codec.getName());
		aclMessage.setOntology(ontology.getName());
		
		return aclMessage;
	}

	protected void printOut(String message)
	{
		System.out.println(getLocalName() + ": " + message);
	}

	protected void printReceivedProtocol(ACLMessage aclMessage)
	{
		/*if (aclMessage != null) 
		{
			SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.SSS");
			Date dt = new Date();
			String dateTime = sdf.format(dt);
			
			String str;
			if (aclMessage.getProtocol() != null)
			{
				str = "--------------------------------------------------------<protocol> "+aclMessage.getProtocol();
			}
			else
			{
				str = "--------------------------------------------------------<NO PROTOCOL SET>";
			}
			
			printOut(str + " received from "+ aclMessage.getSender().getLocalName() + " at " + dateTime);
		}*/
	}
	
	protected void printEntered()
	{
		printOut(Constants.ENTEREDINTOSYSTEM);
	}
	
	protected AID createAndStartAgent(String agentName, String agentClass, Object[] object)
	{
		AID agentAID;
		AgentContainer agentContainer = getContainerController();
		try 
		{
			AgentController agentController = agentContainer.createNewAgent(agentName, agentClass, object);
			agentAID = new AID(agentName, AID.ISLOCALNAME);
			agentController.start();
			
			return agentAID;
		} 
		catch (Exception e) 
		{
			printOut("Exception when creating a new agent (@ Team2BaseAgent.createAndStartAgent())");
			printOut(e.toString());
			return null;
		}
	}
	
	protected void destroyAgentsByName(String... args)
	{
		AgentContainer agentContainer = getContainerController();
		try 
		{
			for (String agentName : args)
			{
				AgentController agentController = agentContainer.getAgent(agentName);
				agentController.kill();
			}
		} 
		catch (ControllerException e) 
		{
			e.printStackTrace();
		}
	}

}
